<?php
namespace Uploadcare;

class File
{
	/**
	 * Uploadcare cdn host
	 *
	 * @var string
	 **/
	private $cdn_host = 'ucarecdn.com';

	/**
	 * Uploadcare file id
	 *
	 * @var string
	 **/
	private $file_id = null;

	/**
	 * Operations and params for operations: crop, resize, scale_crop, effect.
	 *
	 * @var array
	 */
	private $operations = array();

	/**
	 * Uploadcare class instance.
	 *
	 * @var Api
	**/
	private $api = null;

	/**
	 * Operations list
	 **/
	private $operation_list = array('crop', 'resize', 'scale_crop', 'effect');
	
	/**
	 * Cached data
	 *
	 * @var array
	 **/
	private $cached_data = null;	

	/**
	 * Constructs an object for CDN file with specified ID
	 *
	 * @param string $file_id Uploadcare file_id
	 * @param Uploadcare $api Uploadcare class instance
	**/
	public function __construct($file_id, Api $api)
	{
		$this->file_id = $file_id;
		$this->api = $api;
	}

	public function __get($name)
	{
		if ($name == 'data') {
			if (!$this->cached_data) {
				$this->cached_data = (array)$this->api->__preparedRequest(API_TYPE_FILE, REQUEST_TYPE_GET, array('file_id' => $this->file_id));
			}
			return $this->cached_data;
		}
	}	
	
	/**
	 * @return string
	 **/
	public function __toString()
	{
		return $this->getUrl();
	}
	
	/**
	 * Return file_id for this file
	 *
	 * @return string
	 **/
	public function getFileId()
	{
		return $this->file_id;
	}

	/**
	 * Try to store file.
	 *
	 * @param boolean $check_status Check upload status?
	 * @return array
	 **/
	public function store()
	{
		return $this->api->__preparedRequest(API_TYPE_STORE, REQUEST_TYPE_POST, array('file_id' => $this->file_id));
	}
	
	/**
	 * Delete file
	 * 
	 * @return array
	 **/
	public function delete()
	{
		return $this->api->__preparedRequest(API_TYPE_FILE, REQUEST_TYPE_DELETE, array('file_id' => $this->file_id));
	}

	/**
	 * Get url of original image
	 *
	 * @param string $postfix
	 * @return string
	 **/
	public function getUrl($postfix = null)
	{
		$url = sprintf('https://%s/%s/', $this->cdn_host, $this->file_id);

		$operations = array();

		foreach ($this->operations as $i => $operation_item) {
			$part = array();
			foreach (array_keys($operation_item) as $operation_type) {
				$operation_params = $operation_item[$operation_type];
				$part[] = $operation_type;
				switch ($operation_type) {
					case 'crop':
						$part = $this->__addPartSize($part, $operation_params);
						$part = $this->__addPartCenter($part, $operation_params);
						$part = $this->__addPartFillColor($part, $operation_params);
						break;
					case 'resize':
						$part = $this->__addPartSize($part, $operation_params);
						break;
					case 'scale_crop':
						$part = $this->__addPartSize($part, $operation_params);
						$part = $this->__addPartCenter($part, $operation_params);
						break;
					case 'effect':
						$part = $this->__addPartEffect($part, $operation_params);
						break;
					case 'custom':
						$part = array($operation_params);
						break;						
				}
				$part_str = join('/', $part);
				$operations[] = $part_str;
			}
		}

		if (count($operations)) {
			$operations_part = join('/-/', $operations);
			return $url.'-/'.$operations_part.'/'.$postfix;
		} else {
			return $url.$postfix;
		}
	}
	
	/**
	 * Get image tag
	 * 
	 * @param string $postfix File path postfix
	 * @param array $attrs additional attributes
	 * @return string
	 **/
	public function getImgTag($postfix = null, $attribs = array())
	{
		$to_compile = array();
		foreach ($attribs as $key => $value) {
			$to_compile[] = sprintf('%s="%s"', $key, $value);
		}		
		return sprintf('<img src="%s" %s />', $this->getUrl(), join(' ', $to_compile));
	}

	/**
	 * Get object with cropped parameters.
	 *
	 * @param integer $width Crop width
	 * @param integer $height Crop height
	 * @param boolean $center Center crop? true or false (default false).
	 * @param string $fill_color Fill color. If nothig is provided just use false (default false).
	 * @return File
	 */
	public function crop($width, $height, $center = false, $fill_color = false)
	{
		$result = clone $this;
		$result->operations[]['crop'] = array(
				'width' => $width,
				'height' => $height,
				'center' => $center,
				'fill_color' => $fill_color,
		);
		return $result;
	}

	/**
	 * Get object with resized parameters.
	 * Provide width or height or both.
	 * If not width or height are provided exceptions will be thrown!
	 *
	 * @param integer $width Resized image width. Provide false if you resize proportionally.
	 * @param integer $height Resized image height. Provide false if you resize proportionally.
	 * @throws \Exception
	 * @return File
	 **/
	public function resize($width = false, $height = false)
	{
		$result = clone $this;
		if (!$width && !$height) {
			throw new \Exception('Please, provide at least width or height for resize');
		}
		$result->operations[]['resize'] = array(
				'width' => $width,
				'height' => $height,
		);
		return $result;
	}

	/**
	 * Get object with cropped parameters.
	 *
	 * @param integer $width Crop width
	 * @param integer $height Crop height
	 * @param boolean $center Center crop? true or false (default false).
	 * @return File
	 */
	public function scaleCrop($width, $height, $center = false)
	{
		$result = clone $this;
		$result->operations[]['scale_crop'] = array(
				'width' => $width,
				'height' => $height,
				'center' => $center,
		);
		return $result;
	}

	/**
	 * Apply effect
	 *
	 * @param string $effect Effect name
	 * @return File
	 **/
	public function effect($effect)
	{
		$result = clone $this;
		$result->operations[]['effect'] = $effect;
		return $result;
	}
	
	/**
	 * Add any custom operation.
	 *
	 * @param string $operation
	 **/
	public function op($operation)
	{
		$result = clone $this;
		$result->operations[]['custom'] = $operation;
		return $result;
	}	

	/**
	 * Adds part with size for operations
	 *
	 * @param array $part
	 * @param array $params
	 * @return array
	 **/
	private function __addPartSize($part, $params)
	{
		$part[] = sprintf('%sx%s', $params['width'], $params['height']);
		return $part;
	}

	/**
	 * Adds part with center for operations
	 *
	 * @param array $part
	 * @param array $params
	 * @return array
	 **/
	private function __addPartCenter($part, $params)
	{
		if ($params['center'] !== false) {
			$part[] = 'center';
		}
		return $part;
	}

	/**
	 * Adds part with fill color for operations
	 *
	 * @param array $part
	 * @param array $params
	 * @return array
	 **/
	private function __addPartFillColor($part, $params)
	{
		if ($params['fill_color'] !== false) {
			$part[] = $params['fill_color'];
		}
		return $part;
	}

	/**
	 * Adds part with effect for operations
	 *
	 * @param array $part
	 * @param string $effect
	 * @return array
	 **/
	private function __addPartEffect($part, $effect)
	{
		$part[] = $effect;
		return $part;
	}
}